#pragma once

#include "ISubject.h"
#include "IObserver.h"
#include "IChangeManager.h"

class CSubject : public ISubject
{
public:
	BEGIN_DEFINE_CLASS(CLSID_Subject)
		DEFINE_INTERFACE_ENTRY(ISubject)
	END_DEFINE_CLASS()

	CSubject();
	virtual ~CSubject();

	virtual bool IsAttached(viid subjectIID, viid interestedObjectIID,IObserver* observer);
	virtual void Attach(viid subjectIID, viid interestedObjectIID,IObserver* observer);
	virtual void Detach(viid subjectIID, viid interestedObjectIID,IObserver* observer);
	virtual void Update(viid subjectIID, const InterestedObjects& interestedObjects,uint32 data=NULL);
	virtual void Update(viid subjectIID, viid interestedObjectIID,const InterestedObjects& interestedObjects,uint32 data=NULL);

protected:
	IChangeManager* GetChangeManager() const;
	void UpdateDefault(uint32 data=NULL);
};

//////////////////////////////////////////////////////////////////////////
//inline methods
inline CSubject::CSubject()
{
}

inline CSubject::~CSubject()
{
}

inline bool CSubject::IsAttached(viid subjectIID, viid interestedObjectIID,IObserver* observer)
{
	return GetChangeManager()->IsObserverRegistered(subjectIID,interestedObjectIID,observer);
}

inline void CSubject::Attach(viid subjectIID, viid interestedObjectIID,IObserver* observer)
{
	return GetChangeManager()->RegisterObserver(subjectIID,interestedObjectIID,observer);
}

inline void CSubject::Detach(viid subjectIID, viid interestedObjectIID,IObserver* observer)
{
	return GetChangeManager()->UnRegisterObserver(subjectIID,interestedObjectIID,observer);
}

inline void CSubject::Update(viid subjectIID, const InterestedObjects& interestedObjects,uint32 data/*=NULL*/)
{
	IObject* pSelfObj = NULL;
	(ISubject*)(this)->QueryObject(&pSelfObj);
	return GetChangeManager()->ChangeNotify(subjectIID,pSelfObj,interestedObjects,data);
}

inline void CSubject::UpdateDefault(uint32 data/*=NULL*/)
{
	IObject* pSelfObj = NULL;
	(ISubject*)(this)->QueryObject(&pSelfObj);
	return GetChangeManager()->ChangeNotify(IID_Subject,pSelfObj,InterestedObjects::Null(),data);
}

inline void CSubject::Update(viid subjectIID, viid interestedObjectIID,const InterestedObjects& interestedObjects,uint32 data/*=NULL*/)
{
	IObject* pSelfObj = NULL;
	(ISubject*)(this)->QueryObject(&pSelfObj);
	return GetChangeManager()->ChangeNotify(subjectIID,interestedObjectIID,pSelfObj,interestedObjects,data);
}

inline IChangeManager* CSubject::GetChangeManager() const
{
	sys::ObjectPtr objChangeManager;
	VRVERIFY(objChangeManager.CreateObject(CLSID_ChangeManager));
	sys::InterfacePtr<IChangeManager> pIFChangeManager(objChangeManager);
	return pIFChangeManager;
}